Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow insert_all on relation #38899

Merged
merged 1 commit into from
Apr 24, 2020
Merged

Conversation

kamipo
Copy link
Member

@kamipo kamipo commented Apr 8, 2020

This allows to work author.books.insert_all as expected.

@simi
Copy link
Contributor

simi commented Apr 8, 2020

How does this behave for has many through relation now?

@kamipo
Copy link
Member Author

kamipo commented Apr 8, 2020

Doesn't work expected, need to handle that as an error as you did.

@simi
Copy link
Contributor

simi commented Apr 8, 2020

@kamipo I see you're still working on this. Feel free to ping me once you're done, I can take a look as well.

@kamipo
Copy link
Member Author

kamipo commented Apr 8, 2020

I've done.

@simi
Copy link
Contributor

simi commented Apr 8, 2020

@kamipo IMHO InsertAll should be the place where to decide if passed arguments are supported. What is your motivation to move it outside? It is just because currently it is not easy to check for through relation in there?

@kamipo
Copy link
Member Author

kamipo commented Apr 9, 2020

Yes, currently it is not easy to check for through relation not on association relation.

class_eval <<~RUBY
def #{method}(attributes, **kwargs)
if @association.reflection.through_reflection?
raise ArgumentError, "Bulk insert is currently not supported for through relations"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kamipo Can we change the error message to say Bulk insert or update since upsert perform updates? Also, through relations -> has_many :through association if that looks proper to you.

Suggested change
raise ArgumentError, "Bulk insert is currently not supported for through relations"
raise ArgumentError, "Bulk insert or update is currently not supported for has_many :through association"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, is ArgumentError correct here? We haven't implemented bulk insert for has_many through association. Shouldn't it be NotImplementedError?

Copy link
Contributor

@simi simi Apr 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK NotImplementedError is not meant to be raised for missing app features, but for missing platform features. https://ruby-doc.org/core-2.5.0/NotImplementedError.html

@simi
Copy link
Contributor

simi commented Apr 9, 2020

@kamipo I can take a look if there is not any chance to expose this somehow to be accessible in InsertAll. Current way seems to me a little "hackish".

@kamipo
Copy link
Member Author

kamipo commented Apr 9, 2020

Updated the error message at b69ff2ed39c79886ba4b606c2bb75db8fac323a4. @abhaynikam Is it fine for you?

I agree that ArgumentError is not 100% correct, but seems NotImplementedError is also not perfectly match. Possible alternatives are ActiveRecordError, RuntimeError?

@abhaynikam
Copy link
Contributor

LGTM @kamipo 👍, Thanks.

@kamipo
Copy link
Member Author

kamipo commented Apr 9, 2020

Actually we can check whether association relation or not by model.scope_attributes?.respond_to?(:proxy_association), but IMO association relation is an implementation detail, I'd not prefer to use .respond_to?(:proxy_association) (association relation is accidentally exposed in the API doc though).

diff --git a/activerecord/lib/active_record/insert_all.rb b/activerecord/lib/active_record/insert_all.rb
index 3d6d1df18a..fbe7f4fc74 100644
--- a/activerecord/lib/active_record/insert_all.rb
+++ b/activerecord/lib/active_record/insert_all.rb
@@ -13,7 +13,10 @@ def initialize(model, inserts, on_duplicate:, returning: nil, unique_by: nil)
       @model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s)
       @on_duplicate, @returning, @unique_by = on_duplicate, returning, unique_by
 
-      if model.scope_attributes?
+      if scope = model.scope_attributes?
+        if scope.respond_to?(:proxy_association) && scope.proxy_association.reflection.through_reflection?
+          raise ArgumentError, "Bulk insert or upsert is currently not supported for has_many through association"
+        end
         @scope_attributes = model.scope_attributes
         @keys |= @scope_attributes.keys
       end

@simi
Copy link
Contributor

simi commented Apr 9, 2020

@kamipo yes, that's similar to that one I used before. That's hackish as well. I would like to take a look for potential refactoring to get this info easier in InsertAll.

Copy link
Contributor

@kaspth kaspth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything else missing?

@@ -108,7 +114,6 @@ def unique_by_columns
Array(unique_by&.columns)
end


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these newlines were intentional for method grouping.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see... will add newlines back.

@kamipo
Copy link
Member Author

kamipo commented Apr 24, 2020

I will add a bit more tests and a CHANGELOG entry before merging.

@kaspth
Copy link
Contributor

kaspth commented Apr 24, 2020

Awesome, sounds great 🤘

This allows to work `author.books.insert_all` as expected.

Co-authored-by: Josef Šimánek <josef.simanek@gmail.com>
@simi
Copy link
Contributor

simi commented Apr 24, 2020

Great job everyone! I'm putting on my list to investigate through relations support as well.

@kamipo kamipo merged commit 43d3b60 into rails:master Apr 24, 2020
@kamipo kamipo deleted the insert_all_on_relation branch April 24, 2020 16:47
@boblail
Copy link
Contributor

boblail commented Apr 24, 2020

👏 I'm excited for this!!

@kamipo kamipo mentioned this pull request Apr 4, 2023
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants